package com.csmy.my.center.util;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.CodeSource;
import java.security.MessageDigest;
import java.security.ProtectionDomain;
import java.security.SecureRandom;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.servlet.http.HttpServletRequest;

import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.struts2.ServletActionContext;

import sun.misc.BASE64Encoder;

import com.csmy.my.center.util.dataconvert.Dto;
import com.csmy.my.center.util.dataconvert.TypeCaseHelper;
import com.csmy.my.center.util.dataconvert.impl.BaseDto;

/**
 * 常见的辅助类
 * 
 * @author wgp
 * @since 2013-01-15
 */
public class CTUtils {

	//private static Log log = LogFactory.getLog(CTUtils.class);

	/**
	 * DES算法密钥
	 */
	private static final byte[] DES_KEY = { 21, 1, -110, 82, -32, -85, -128,
			-65 };

	private static String HanDigiStr[] = new String[] { "零", "壹", "贰", "叁",
			"肆", "伍", "陆", "柒", "捌", "玖" };

	private static String HanDiviStr[] = new String[] { "", "拾", "佰", "仟", "万",
			"拾", "佰", "仟", "亿", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾",
			"佰", "仟", "万", "拾", "佰", "仟" };

	/**
	 * 判断对象是否Empty(null或元素为0)<br>
	 * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
	 * 
	 * @param pObj
	 *            待检查对象
	 * @return boolean 返回的布尔值
	 */
	public static boolean isEmpty(Object pObj) {
		if (pObj == null)
			return true;
		if (pObj == "")
			return true;
		if (pObj instanceof String) {
			if (((String) pObj).length() == 0) {
				return true;
			}
		} else if (pObj instanceof Collection) {
			if (((Collection) pObj).size() == 0) {
				return true;
			}
		} else if (pObj instanceof Map) {
			if (((Map) pObj).size() == 0) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 判断对象是否为NotEmpty(!null或元素>0)<br>
	 * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
	 * 
	 * @param pObj
	 *            待检查对象
	 * @return boolean 返回的布尔值
	 */
	public static boolean isNotEmpty(Object pObj) {
		if (pObj == null)
			return false;
		if (pObj == "")
			return false;
		if (pObj instanceof String) {
			if (((String) pObj).length() == 0) {
				return false;
			}
		} else if (pObj instanceof Collection) {
			if (((Collection) pObj).size() == 0) {
				return false;
			}
		} else if (pObj instanceof Map) {
			if (((Map) pObj).size() == 0) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 判断一个字符串是否由数字、字母、数字字母组成
	 * 
	 * @param pStr
	 *            需要判断的字符串
	 * @param pStyle
	 *            判断规则
	 * @return boolean 返回的布尔值
	 */
	public static boolean isTheStyle(String pStr, String pStyle) {
		for (int i = 0; i < pStr.length(); i++) {
			char c = pStr.charAt(i);
			if (pStyle.equals(CTConstants.S_STYLE_N)) {
				if (!Character.isDigit(c))
					return false;
			} else if (pStyle.equals(CTConstants.S_STYLE_L)) {
				if (!Character.isLetter(c))
					return false;
			} else if (pStyle.equals(CTConstants.S_STYLE_NL)) {
				if (Character.isLetterOrDigit(c))
					return false;
			}
		}
		return true;
	}

	/**
	 * JavaBean之间对象属性值拷贝
	 * 
	 * @param pFromObj
	 *            Bean源对象
	 * @param pToObj
	 *            Bean目标对象
	 */
	public static void copyPropBetweenBeans(Object pFromObj, Object pToObj) {
		if (pToObj != null) {
			try {
				BeanUtils.copyProperties(pToObj, pFromObj);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 将JavaBean对象中的属性值拷贝到Dto对象
	 * 
	 * @param pFromObj
	 *            JavaBean对象源
	 * @param pToDto
	 *            Dto目标对象
	 */
	public static void copyPropFromBean2Dto(Object pFromObj, Dto pToDto) {
		if (pToDto != null) {
			try {
				pToDto.putAll(BeanUtils.describe(pFromObj));
				// BeanUtils自动加入了一个Key为class的键值,故将其移除
				pToDto.remove("class");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 将传入的身份证号码进行校验，并返回一个对应的18位身份证
	 * 
	 * @param personIDCode
	 *            身份证号码
	 * @return String 十八位身份证号码
	 * @throws 无效的身份证号
	 */
	public static String getFixedPersonIDCode(String personIDCode)
			throws Exception {
		if (personIDCode == null)
			throw new Exception("输入的身份证号无效，请检查");

		if (personIDCode.length() == 18) {
			if (isIdentity(personIDCode))
				return personIDCode;
			else
				throw new Exception("输入的身份证号无效，请检查");
		} else if (personIDCode.length() == 15)
			return fixPersonIDCodeWithCheck(personIDCode);
		else
			throw new Exception("输入的身份证号无效，请检查");
	}

	/**
	 * 修补15位居民身份证号码为18位，并校验15位身份证有效性
	 * 
	 * @param personIDCode
	 *            十五位身份证号码
	 * @return String 十八位身份证号码
	 * @throws 无效的身份证号
	 */
	public static String fixPersonIDCodeWithCheck(String personIDCode)
			throws Exception {
		if (personIDCode == null || personIDCode.trim().length() != 15)
			throw new Exception("输入的身份证号不足15位，请检查");

		if (!isIdentity(personIDCode))
			throw new Exception("输入的身份证号无效，请检查");

		return fixPersonIDCodeWithoutCheck(personIDCode);
	}

	/**
	 * 修补15位居民身份证号码为18位，不校验身份证有效性
	 * 
	 * @param personIDCode
	 *            十五位身份证号码
	 * @return 十八位身份证号码
	 * @throws 身份证号参数不是15位
	 */
	public static String fixPersonIDCodeWithoutCheck(String personIDCode)
			throws Exception {
		if (personIDCode == null || personIDCode.trim().length() != 15)
			throw new Exception("输入的身份证号不足15位，请检查");

		String id17 = personIDCode.substring(0, 6) + "19"
				+ personIDCode.substring(6, 15); // 15位身份证补'19'

		char[] code = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' }; // 11个校验码字符
		int[] factor = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1 }; // 18个加权因子
		int[] idcd = new int[18];
		int sum; // 根据公式 ∑(ai×Wi) 计算
		int remainder; // 第18位校验码
		for (int i = 0; i < 17; i++) {
			idcd[i] = Integer.parseInt(id17.substring(i, i + 1));
		}
		sum = 0;
		for (int i = 0; i < 17; i++) {
			sum = sum + idcd[i] * factor[i];
		}
		remainder = sum % 11;
		String lastCheckBit = String.valueOf(code[remainder]);
		return id17 + lastCheckBit;
	}

	/**
	 * 判断是否是有效的18位或15位居民身份证号码
	 * 
	 * @param identity
	 *            18位或15位居民身份证号码
	 * @return 是否为有效的身份证号码
	 */
	public static boolean isIdentity(String identity) {
		if (identity == null)
			return false;
		if (identity.length() == 18 || identity.length() == 15) {
			String id15 = null;
			if (identity.length() == 18)
				id15 = identity.substring(0, 6) + identity.substring(8, 17);
			else
				id15 = identity;
			try {
				Long.parseLong(id15); // 校验是否为数字字符串

				String birthday = "19" + id15.substring(6, 12);
				SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
				sdf.parse(birthday); // 校验出生日期
				if (identity.length() == 18
						&& !fixPersonIDCodeWithoutCheck(id15).equals(identity))
					return false; // 校验18位身份证
			} catch (Exception e) {
				return false;
			}
			return true;
		} else
			return false;
	}

	/**
	 * 从身份证号中获取出生日期，身份证号可以为15位或18位
	 * 
	 * @param identity
	 *            身份证号
	 * @return 出生日期
	 * @throws 身份证号出生日期段有误
	 */
	public static Timestamp getBirthdayFromPersonIDCode(String identity)
			throws Exception {
		String id = getFixedPersonIDCode(identity);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		try {
			Timestamp birthday = new Timestamp(sdf.parse(id.substring(6, 14))
					.getTime());
			return birthday;
		} catch (ParseException e) {
			throw new Exception("不是有效的身份证号，请检查");
		}
	}

	/**
	 * 从身份证号获取性别
	 * 
	 * @param identity
	 *            身份证号
	 * @return 性别代码
	 * @throws Exception
	 *             无效的身份证号码
	 */
	public static String getGenderFromPersonIDCode(String identity)
			throws Exception {
		String id = getFixedPersonIDCode(identity);
		char sex = id.charAt(16);
		return sex % 2 == 0 ? "2" : "1";
	}

	/**
	 * 将货币转换为大写形式(类内部调用)
	 * 
	 * @param val
	 * @return String
	 */
	private static String PositiveIntegerToHanStr(String NumStr) {
		// 输入字符串必须正整数，只允许前导空格(必须右对齐)，不宜有前导零
		String RMBStr = "";
		boolean lastzero = false;
		boolean hasvalue = false; // 亿、万进位前有数值标记
		int len, n;
		len = NumStr.length();
		if (len > 15)
			return "数值过大!";
		for (int i = len - 1; i >= 0; i--) {
			if (NumStr.charAt(len - i - 1) == ' ')
				continue;
			n = NumStr.charAt(len - i - 1) - '0';
			if (n < 0 || n > 9)
				return "输入含非数字字符!";

			if (n != 0) {
				if (lastzero)
					RMBStr += HanDigiStr[0]; // 若干零后若跟非零值，只显示一个零
				// 除了亿万前的零不带到后面
				// if( !( n==1 && (i%4)==1 && (lastzero || i==len-1) ) )
				// 如十进位前有零也不发壹音用此行
				if (!(n == 1 && (i % 4) == 1 && i == len - 1)) // 十进位处于第一位不发壹音
					RMBStr += HanDigiStr[n];
				RMBStr += HanDiviStr[i]; // 非零值后加进位，个位为空
				hasvalue = true; // 置万进位前有值标记

			} else {
				if ((i % 8) == 0 || ((i % 8) == 4 && hasvalue)) // 亿万之间必须有非零值方显示万
					RMBStr += HanDiviStr[i]; // “亿”或“万”
			}
			if (i % 8 == 0)
				hasvalue = false; // 万进位前有值标记逢亿复位
			lastzero = (n == 0) && (i % 4 != 0);
		}

		if (RMBStr.length() == 0)
			return HanDigiStr[0]; // 输入空字符或"0"，返回"零"
		return RMBStr;
	}

	/**
	 * 将货币转换为大写形式
	 * 
	 * @param val
	 *            传入的数据
	 * @return String 返回的人民币大写形式字符串
	 */
	public static String numToRMBStr(double val) {
		String SignStr = "";
		String TailStr = "";
		long fraction, integer;
		int jiao, fen;

		if (val < 0) {
			val = -val;
			SignStr = "负";
		}
		if (val > 99999999999999.999 || val < -99999999999999.999)
			return "数值位数过大!";
		// 四舍五入到分
		long temp = Math.round(val * 100);
		integer = temp / 100;
		fraction = temp % 100;
		jiao = (int) fraction / 10;
		fen = (int) fraction % 10;
		if (jiao == 0 && fen == 0) {
			TailStr = "整";
		} else {
			TailStr = HanDigiStr[jiao];
			if (jiao != 0)
				TailStr += "角";
			// 零元后不写零几分
			if (integer == 0 && jiao == 0)
				TailStr = "";
			if (fen != 0)
				TailStr += HanDigiStr[fen] + "分";
		}
		// 下一行可用于非正规金融场合，0.03只显示“叁分”而不是“零元叁分”
		// if( !integer ) return SignStr+TailStr;
		return SignStr + PositiveIntegerToHanStr(String.valueOf(integer)) + "元"
				+ TailStr;
	}

	/**
	 * 获取指定年份和月份对应的天数
	 * 
	 * @param year
	 *            指定的年份
	 * @param month
	 *            指定的月份
	 * @return int 返回天数
	 */
	public static int getDaysInMonth(int year, int month) {
		if ((month == 1) || (month == 3) || (month == 5) || (month == 7)
				|| (month == 8) || (month == 10) || (month == 12)) {
			return 31;
		} else if ((month == 4) || (month == 6) || (month == 9)
				|| (month == 11)) {
			return 30;
		} else {
			if (((year % 4) == 0) && ((year % 100) != 0) || ((year % 400) == 0)) {
				return 29;
			} else {
				return 28;
			}
		}
	}

	/**
	 * 根据所给的起止时间来计算间隔的天数
	 * 
	 * @param startDate
	 *            起始时间
	 * @param endDate
	 *            结束时间
	 * @return int 返回间隔天数
	 */
	public static int getIntervalDays(java.util.Date startDate,java.util.Date endDate) {
		long startdate = startDate.getTime();
		long enddate = endDate.getTime();
		long interval = enddate - startdate;
		int intervalday = (int) (interval / (1000 * 60 * 60 * 24));
		StringUtil.xprint("日期相隔天数为："+intervalday);
		return intervalday;
	}
	
	public static String getCountType(java.util.Date start,java.util.Date end) {
		String type = "d";//默认按照天统计 
		int days = getIntervalDays(start, end);
		if(days==0 || days < 1){
			type="h";
		}
		if(1 <= days && days <=30){
			type="d";
		}
		if(30 < days && days <=90){
			type="w";
		}
		
		if(days > 90){
			type="m";
		}
		return type;
	}
	
	/**
	 * 第一个日期对象减除第二个日期对象，返回long类型数据；(单位毫秒）
	 * @param d1 第一个日期对象
	 * @param d2 第二个日期对象
	 * @return
	 * @author powerxsu
	 */
	public static long sub(Date d1,Date d2){
		if(d1==null||d2==null)return 0;
		else
		return d1.getTime()-d2.getTime();
	}
	

	/**
	 * 根据所给的起止时间来计算间隔的月数
	 * 
	 * @param startDate
	 *            起始时间
	 * @param endDate
	 *            结束时间
	 * @return int 返回间隔月数
	 */
	public static int getIntervalMonths(java.sql.Date startDate,java.sql.Date endDate) {
		Calendar startCal = Calendar.getInstance();
		startCal.setTime(startDate);
		Calendar endCal = Calendar.getInstance();
		endCal.setTime(endDate);
		int startDateM = startCal.MONTH;
		int startDateY = startCal.YEAR;
		int enddatem = endCal.MONTH;
		int enddatey = endCal.YEAR;
		int interval = (enddatey * 12 + enddatem)- (startDateY * 12 + startDateM);
		return interval;
	}
	
	
	
	/**
	 * 获取指定日期所在月的最后一天
	 * 
	 * @param vDate
	 * @return
	 */
	public static String getCurrentMonthLastDay(Date vDate) {
		Calendar ca = Calendar.getInstance();
		ca.setTime(vDate); // vDate 为你要获取的那个月的时间
		ca.set(Calendar.DAY_OF_MONTH, 1);//第一天
		Date firstDate = ca.getTime();
		ca.add(Calendar.MONTH, 1);
		ca.add(Calendar.DAY_OF_MONTH, -1);
		Date lastDate = ca.getTime();//最后一天
		SimpleDateFormat simpleFormate = new SimpleDateFormat(CTConstants.FORMAT_DateTime);
        return simpleFormate.format(lastDate);   
	}

	/**
	 * 返回当前日期时间字符串<br>
	 * 默认格式:yyyy-mm-dd hh:mm:ss
	 * 
	 * @return String 返回当前字符串型日期时间
	 */
	public static String getCurrentTime() {
		String returnStr = null;
		SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = new Date();
		returnStr = f.format(date);
		return returnStr;
	}

	/**
	 * 根据long类型日期和格式转换日期为字符串
	 * 
	 * @param date
	 *            例如12752464646546
	 * @param format
	 *            例如：yyyy-MM-dd HH:mm:ss
	 */
	public static String date2String(long date, String format) {
		Date cDate = new Date(date);
		SimpleDateFormat f = new SimpleDateFormat(format);
		return f.format(cDate);
	}
	
	/**
	 * 根据String类型日期和格式转换日期为字符串
	 * 
	 * @param String
	 *            例如2012-02-01 56:55:56
	 * @param format
	 *            例如：yyyy-MM-dd HH:mm:ss
	 */
	public static String date2Str(String date, String format) {
		Date cDate = new Date(date);
		SimpleDateFormat f = new SimpleDateFormat(format);
		return f.format(cDate);
	}
	
	/**
	 * 根据日期和格式转换日期为字符串
	 * 
	 * @param date new Date();
	 * @param format
	 *            例如：yyyy-MM-dd HH:mm:ss
	 */
	public static String dateToStr(Date cDate, String format) {
		SimpleDateFormat f = new SimpleDateFormat(format);
		return f.format(cDate);
	}

	/**
	 * 返回自定义格式的当前日期时间字符串
	 * 
	 * @param format
	 *            格式规则
	 * @return String 返回当前字符串型日期时间
	 */
	public static String getCurrentTime(String format) {
		String returnStr = null;
		SimpleDateFormat f = new SimpleDateFormat(format);
		Date date = new Date();
		returnStr = f.format(date);
		return returnStr;
	}

	/**
	 * 返回当前字符串型日期
	 * 
	 * @return String 返回的字符串型日期
	 */
	public static String getCurDate() {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat simpledateformat = new SimpleDateFormat("yyyy-MM-dd");
		String strDate = simpledateformat.format(calendar.getTime());
		return strDate;
	}
	
	
	/**
	 * 根据给出的日期计算日期
	 * @param day
	 * @return
	 */
	public static String getDateByUDay (int day) {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		//返回给出的天指定的日期
		calendar.add(Calendar.DAY_OF_MONTH,day);
		return sdf.format(calendar.getTime());
	}
	
	/**
	 * 计算日期差
	 * @param date1
	 * @param date2
	 * @return
	 * @throws ParseException 
	 */
	public static int getSubDay(String date1,String date2) throws ParseException {
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar cal1=Calendar.getInstance();
		cal1.setTime(sdf.parse(date1));
		Calendar cal2=Calendar.getInstance();
		cal2.setTime(sdf.parse(date2));
		long l=cal2.getTimeInMillis()-cal1.getTimeInMillis();
		int days=new Long(l/(1000*60*60*24)).intValue();
		System.out.println("2个日期之间相差："+days+"天。");
		return days;
	}
	
	/**
	 * 返回当前字符串型日期
	 * 
	 * @return String 返回的字符串型日期
	 */
	public static String getCurDateNoSplit() {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat simpledateformat = new SimpleDateFormat("yyyyMMdd");
		String strDate = simpledateformat.format(calendar.getTime());
		return strDate;
	}
	
	/**
	 * 返回当前字符串型日期
	 * 
	 * @return String 返回的字符串型日期
	 */
	public static String getCurDateNoSplitTime() {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat simpledateformat = new SimpleDateFormat("yyyyMMddHHmmss");
		String strDate = simpledateformat.format(calendar.getTime());
		return strDate;
	}
	
	
	/**
	 * 返回当前字符串型日期带中文
	 * 
	 * @return String 返回的字符串型日期
	 */
	public static String getCurDateZN() {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat simpledateformat = new SimpleDateFormat("yyyy年MM月dd日");
		String strDate = simpledateformat.format(calendar.getTime());
		return strDate;
	}

	/**
	 * 返回TimeStamp对象
	 * 
	 * @return
	 */
	public static Timestamp getCurrentTimestamp() {
		Object obj = TypeCaseHelper.convert(getCurrentTime(), "Timestamp",
				"yyyy-MM-dd HH:mm:ss");
		if (obj != null)
			return (Timestamp) obj;
		else
			return null;
	}

	/**
	 * 将字符串型日期转换为日期型
	 * 
	 * @param strDate
	 *            字符串型日期
	 * @param srcDateFormat
	 *            源日期格式
	 * @param dstDateFormat
	 *            目标日期格式
	 * @return Date 返回的util.Date型日期
	 */
	public static Date stringToDate(String strDate, String srcDateFormat,
			String dstDateFormat) {
		Date rtDate = null;
		Date tmpDate = (new SimpleDateFormat(srcDateFormat)).parse(strDate,
				new ParsePosition(0));
		String tmpString = null;
		if (tmpDate != null)
			tmpString = (new SimpleDateFormat(dstDateFormat)).format(tmpDate);
		if (tmpString != null)
			rtDate = (new SimpleDateFormat(dstDateFormat)).parse(tmpString,
					new ParsePosition(0));
		return rtDate;
	}

	/**
	 * 日期转换
	 * 
	 * @param datestr
	 * @return
	 */
	public static Date strToDate(String datestr) {
		String fomate = "yyyy-MM-dd";
		SimpleDateFormat sf = new SimpleDateFormat(fomate);
		Date date = new Date();
		try {
			date = sf.parse(datestr);
			return date;
		} catch (Exception e) {
			System.out.println("日期转换失败");
		}
		return null;
	}
	
	/**
	 * 日期转换（包含时间）
	 * 
	 * @param datestr
	 * @return
	 */
	public static Date strToDateTime(String datestr) {
		String fomate = "yyyy-MM-dd HH:mm:ss";
		if(datestr!=null && datestr.indexOf("T")!=-1){
			fomate = "yyyy-MM-dd'T'HH:mm:ss'Z'";
		}
		SimpleDateFormat sf = new SimpleDateFormat(fomate);
		Date date = new Date();
		try {
			date = sf.parse(datestr);
			return date;
		} catch (Exception e) {
			System.out.println("日期转换失败");
		}
		return null;
	}
	

	/**
	 * 根据提供的天数获取开始日期和结束日期 例如：获取近三天 的开始和结束日期
	 * 
	 * @param day
	 * @return
	 */
	public static String getDateByDay(int day) {
		// 初始化查询日期条件
		SimpleDateFormat sdf = new SimpleDateFormat(CTConstants.FORMAT_DateTime);
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DATE, -day);
		return sdf.format(cal.getTime());
	}
	
	/**
	 * 根据提供的天数获取开始日期和结束日期 例如：获取近三天 的开始和结束日期
	 * 
	 * @param day
	 * @return
	 */
	public static String getDateByDay(int day,String format) {
		// 初始化查询日期条件
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DATE, -day);
		return sdf.format(cal.getTime());
	}

	/**
	 * 合并字符串数组
	 * 
	 * @param a
	 *            字符串数组0
	 * @param b
	 *            字符串数组1
	 * @return 返回合并后的字符串数组
	 */
	public static String[] mergeStringArray(String[] a, String[] b) {
		if (a.length == 0 || isEmpty(a))
			return b;
		if (b.length == 0 || isEmpty(b))
			return a;
		String[] c = new String[a.length + b.length];
		for (int m = 0; m < a.length; m++) {
			c[m] = a[m];
		}
		for (int i = 0; i < b.length; i++) {
			c[a.length + i] = b[i];
		}
		return c;
	}

	/**
	 * 对文件流输出下载的中文文件名进行编码 屏蔽各种浏览器版本的差异性
	 */
	public static String encodeChineseDownloadFileName(
			HttpServletRequest request, String pFileName) {
		String agent = request.getHeader("USER-AGENT");
		try {
			if (null != agent && -1 != agent.indexOf("MSIE")) {
				pFileName = URLEncoder.encode(pFileName, "utf-8");
			} else {
				pFileName = new String(pFileName.getBytes("utf-8"), "iso8859-1");
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return pFileName;
	}

	/**
	 * 根据日期获取星期
	 * 
	 * @param strdate
	 * @return
	 */
	public static String getWeekDayByDate(String strdate) {
		final String dayNames[] = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五",
				"星期六" };
		SimpleDateFormat sdfInput = new SimpleDateFormat("yyyy-MM-dd");
		Calendar calendar = Calendar.getInstance();
		Date date = new Date();
		try {
			date = sdfInput.parse(strdate);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		calendar.setTime(date);
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
		if (dayOfWeek < 0)
			dayOfWeek = 0;
		return dayNames[dayOfWeek];
	}

	/**
	 * 判断是否是IE浏览器
	 * 
	 * @param userAgent
	 * @return
	 */
	public static boolean isIE(HttpServletRequest request) {
		String userAgent = request.getHeader("USER-AGENT").toLowerCase();
		boolean isIe = true;
		int index = userAgent.indexOf("msie");
		if (index == -1) {
			isIe = false;
		}
		return isIe;
	}

	/**
	 * 判断是否是Chrome浏览器
	 * 
	 * @param userAgent
	 * @return
	 */
	public static boolean isChrome(HttpServletRequest request) {
		String userAgent = request.getHeader("USER-AGENT").toLowerCase();
		boolean isChrome = true;
		int index = userAgent.indexOf("chrome");
		if (index == -1) {
			isChrome = false;
		}
		return isChrome;
	}

	/**
	 * 判断是否是Firefox浏览器
	 * 
	 * @param userAgent
	 * @return
	 */
	public static boolean isFirefox(HttpServletRequest request) {
		String userAgent = request.getHeader("USER-AGENT").toLowerCase();
		boolean isFirefox = true;
		int index = userAgent.indexOf("firefox");
		if (index == -1) {
			isFirefox = false;
		}
		return isFirefox;
	}
	
	/**
	 * 根据请求获取浏览器版本
	 * @return
	 */
	public static String getExplorerVersion(HttpServletRequest request){
		String version = "";
		if(isIE(request)){
			version = "IE";
		}else if(isFirefox(request)){
			version = "Firefox";
		}else if(isChrome(request)){
			version = "Chrome";
		}else{
			version = "IE";//默认IE
		}
		return version;
	}
	

	/**
	 * 获取客户端类型
	 * 
	 * @param userAgent
	 * @return
	 */
	public static String getClientExplorerType(HttpServletRequest request) {
		String userAgent = request.getHeader("USER-AGENT").toLowerCase();
		String explorer = "非主流浏览器";
		if (isIE(request)) {
			int index = userAgent.indexOf("msie");
			explorer = userAgent.substring(index, index + 8);
		} else if (isChrome(request)) {
			int index = userAgent.indexOf("chrome");
			explorer = userAgent.substring(index, index + 12);
		} else if (isFirefox(request)) {
			int index = userAgent.indexOf("firefox");
			explorer = userAgent.substring(index, index + 11);
		}
		return explorer.toUpperCase();
	}

	/**
	 * 基于MD5算法的单向加密
	 * 
	 * @param strSrc
	 *            明文
	 * @return 返回密文
	 */
	public static String encryptBasedMd5(String strSrc) {
		String outString = null;
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			byte[] outByte = md5.digest(strSrc.getBytes("UTF-8"));
			outString = outByte.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return outString;
	}
	
	/**
	 * 基于base64编码加密
	 * @param enStr
	 * @return
	 */
	public static String encryptBased64(String enStr) {
		String outString = null;
		try {
			byte[] outByte = _Base64.encode(enStr.getBytes());
			outString = new String(outByte);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return outString;
	}
	
	/**
	 * 基于base64编码解密
	 * @param deStr
	 * @return
	 */
	public static String decryptBased64(String deStr) {
		String outString = null;
		try {
			byte [] outByte = _Base64.decode(deStr);
			outString = new String(outByte);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return outString;
	}
	

	/**
	 * 数据加密，算法（DES）
	 * 
	 * @param data
	 *            要进行加密的数据
	 * @return 加密后的数据
	 */
	public static String encryptBasedDes(String data) {
		String encryptedData = null;
		try {
			// DES算法要求有一个可信任的随机数源
			SecureRandom sr = new SecureRandom();
			DESKeySpec deskey = new DESKeySpec(DES_KEY);
			// 创建一个密匙工厂，然后用它把DESKeySpec转换成一个SecretKey对象
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey key = keyFactory.generateSecret(deskey);
			// 加密对象
			Cipher cipher = Cipher.getInstance("DES");
			cipher.init(Cipher.ENCRYPT_MODE, key, sr);
			// 加密，并把字节数组编码成字符串
			encryptedData = new BASE64Encoder().encode(cipher.doFinal(data
					.getBytes()));
		} catch (Exception e) {
			throw new RuntimeException("加密错误，错误信息：", e);
		}
		return encryptedData;
	}

	/**
	 * 数据解密，算法（DES）
	 * 
	 * @param cryptData
	 *            加密数据
	 * @return 解密后的数据
	 */
	public static String decryptBasedDes(String cryptData) {
		String decryptedData = null;
		try {
			// DES算法要求有一个可信任的随机数源
			SecureRandom sr = new SecureRandom();
			DESKeySpec deskey = new DESKeySpec(DES_KEY);
			// 创建一个密匙工厂，然后用它把DESKeySpec转换成一个SecretKey对象
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey key = keyFactory.generateSecret(deskey);
			// 解密对象
			Cipher cipher = Cipher.getInstance("DES");
			cipher.init(Cipher.DECRYPT_MODE, key, sr);
			// 把字符串解码为字节数组，并解密
			decryptedData = new String(cipher
					.doFinal(new sun.misc.BASE64Decoder()
							.decodeBuffer(cryptData)));
		} catch (Exception e) {
			throw new RuntimeException("解密错误，错误信息：", e);
		}
		return decryptedData;
	}

	/**
	 * 判断缺省数据源的JDBC类型：Oracle
	 * 
	 * @return
	 */
	public static boolean defaultJdbcTypeOracle() {
		boolean out = false;
		String jdbcType = System.getProperty("g4.JdbcType");
		if (jdbcType.equalsIgnoreCase("oracle")) {
			out = true;
		}
		return out;
	}

	/**
	 * 判断缺省数据源的JDBC类型：Mysql
	 * 
	 * @return
	 */
	public static boolean defaultJdbcTypeMysql() {
		boolean out = false;
		String jdbcType = System.getProperty("g4.JdbcType");
		if (jdbcType.equalsIgnoreCase("mysql")) {
			out = true;
		}
		return out;
	}
	
	
	/**
	 * 过滤特殊字符
	 * 
	 * @param str
	 * @return
	 * @throws PatternSyntaxException
	 */
	public static String specialStrFilter(String str)
			throws PatternSyntaxException {
		String regEx = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
		Pattern p = Pattern.compile(regEx);
		Matcher m = p.matcher(str);
		return m.replaceAll("").trim();
	} 

	/**
	 * JS输出含有\n的特殊处理
	 * 
	 * @param pStr
	 * @return
	 */
	public static String replace4JsOutput(String pStr) {
		pStr = pStr.replace("\r\n", "<br/>&nbsp;&nbsp;");
		pStr = pStr.replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
		pStr = pStr.replace(" ", "&nbsp;");
		return pStr;
	}

	/**
	 * 获取class文件所在绝对路径
	 * 
	 * @param cls
	 * @return
	 * @throws IOException
	 */
	public static String getPathFromClass(Class cls) {
		String path = null;
		if (cls == null) {
			throw new NullPointerException();
		}
		URL url = getClassLocationURL(cls);
		if (url != null) {
			path = url.getPath();
			if ("jar".equalsIgnoreCase(url.getProtocol())) {
				try {
					path = new URL(path).getPath();
				} catch (MalformedURLException e) {
				}
				int location = path.indexOf("!/");
				if (location != -1) {
					path = path.substring(0, location);
				}
			}
			File file = new File(path);
			try {
				path = file.getCanonicalPath();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return path;
	}

	/**
	 * 这个方法可以通过与某个类的class文件的相对路径来获取文件或目录的绝对路径。 通常在程序中很难定位某个相对路径，特别是在B/S应用中。
	 * 通过这个方法，我们可以根据我们程序自身的类文件的位置来定位某个相对路径。
	 * 比如：某个txt文件相对于程序的Test类文件的路径是../../resource/test.txt，
	 * 那么使用本方法Path.getFullPathRelateClass("../../resource/test.txt",Test.class)
	 * 得到的结果是txt文件的在系统中的绝对路径。
	 * 
	 * @param relatedPath
	 *            相对路径
	 * @param cls
	 *            用来定位的类
	 * @return 相对路径所对应的绝对路径
	 * @throws IOException
	 *             因为本方法将查询文件系统，所以可能抛出IO异常
	 */
	public static String getFullPathRelateClass(String relatedPath, Class cls) {
		String path = null;
		if (relatedPath == null) {
			throw new NullPointerException();
		}
		String clsPath = getPathFromClass(cls);
		File clsFile = new File(clsPath);
		String tempPath = clsFile.getParent() + File.separator + relatedPath;
		File file = new File(tempPath);
		try {
			path = file.getCanonicalPath();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return path;
	}

	/**
	 * 获取类的class文件位置的URL
	 * 
	 * @param cls
	 * @return
	 */
	private static URL getClassLocationURL(final Class cls) {
		if (cls == null)
			throw new IllegalArgumentException("null input: cls");
		URL result = null;
		final String clsAsResource = cls.getName().replace('.', '/').concat(
				".class");
		final ProtectionDomain pd = cls.getProtectionDomain();
		if (pd != null) {
			final CodeSource cs = pd.getCodeSource();
			if (cs != null)
				result = cs.getLocation();
			if (result != null) {
				if ("file".equals(result.getProtocol())) {
					try {
						if (result.toExternalForm().endsWith(".jar")
								|| result.toExternalForm().endsWith(".zip"))
							result = new URL("jar:".concat(
									result.toExternalForm()).concat("!/")
									.concat(clsAsResource));
						else if (new File(result.getFile()).isDirectory())
							result = new URL(result, clsAsResource);
					} catch (MalformedURLException ignore) {
					}
				}
			}
		}
		if (result == null) {
			final ClassLoader clsLoader = cls.getClassLoader();
			result = clsLoader != null ? clsLoader.getResource(clsAsResource)
					: ClassLoader.getSystemResource(clsAsResource);
		}
		return result;
	}

	/**
	 * 获取start到end区间的随机数,不包含start+end
	 * @param start
	 * @param end
	 * @return
	 */
	public static BigDecimal getRandom(int start, int end) {
		return new BigDecimal(start + Math.random() * end);
	}
	
	/**
	 * 获取全局参数
	 * @param attr_name
	 * @return
	 */
	public static Object getContextAtrribute(String attr_name) {
		return ServletActionContext.getServletContext().getAttribute(attr_name);
	}
	
	/**
	 * 获取全局参数
	 * @param attr_name
	 * @return
	 */
	public static Object getContextAtrribute(String attr_name,HttpServletRequest request) {
		return request.getSession().getServletContext().getAttribute(attr_name);
	}
	
	/**
	 * 设置全局参数
	 * @param attr_name
	 * @param object
	 */
	public void setContextAtrribute(String attr_name,Object object) {
	    ServletActionContext.getServletContext().setAttribute(attr_name, object);
	}
	
	/**
	 * 获取全局数据对象
	 * @return
	 */
	public static Dto getContextDto() {
		return (BaseDto)ServletActionContext.getServletContext().getAttribute(CTConstants.USER_PERMIT_LIST);
	}
	
	/**
	 * 获取全局参数
	 * @param param_key
	 * @return
	 */
	public static String getParamValue(String param_key,HttpServletRequest request) {
		String param_value=null;
		Dto paramDto = (BaseDto)request.getSession().getServletContext().getAttribute(CTConstants.CT_PARAM_LIST);
		if(isNotEmpty(paramDto)){
			Dto perDto = (BaseDto)paramDto.get(param_key);
			if(isNotEmpty(perDto)){
				param_value = perDto.getAsString("param_value");
			}
		}
		return param_value;
	}
	
	/**
	 * 获取全局参数到请求中
	 * @param param_key
	 * @return
	 */
	public static void getParamToReq(HttpServletRequest request) {
		Dto paramDto = (BaseDto)ServletActionContext.getServletContext().getAttribute(CTConstants.CT_PARAM_LIST);
		if(isNotEmpty(paramDto)){
			Dto perDto = null;
			Iterator<String>  iterator = paramDto.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				perDto = (BaseDto)paramDto.get(key);
				request.setAttribute(perDto.getAsString("param_key"), perDto.getAsString("param_value"));
			}
		}
	}
	
	/**
	 * 获取全局参数
	 * @param param_key
	 * @return
	 */
	public static String getParamValue(String param_key) {
		try {
			String param_value=null;
			Dto paramDto = (BaseDto)ServletActionContext.getServletContext().getAttribute(CTConstants.CT_PARAM_LIST);
			if(isNotEmpty(paramDto)){
				Dto perDto = (BaseDto)paramDto.get(param_key);
				if(isNotEmpty(perDto)){
					param_value = perDto.getAsString("param_value");
				}
			}
			return param_value;
		} catch (Exception e) {
			return "";
		}
		
	}
	
	/**
	 * 获取上下文中全局变量
	 * @param name 标识符
	 * @return
	 */
	public static Dto getContextProperty(String name) {
		return (BaseDto)getContextDto().get(name);
	}
	
	/**
	 * 转换拼音
	 * @param name
	 * @param all_word
	 * @return
	 */
	public static String getSpellWord(String name,boolean all_word) {
		if(!all_word){
			return new ZHToEN().converterToFirstSpell(name);
		}else{
			try {
				return new ZHToEN().getPingyin(name);
			} catch (BadHanyuPinyinOutputFormatCombination e) {
				e.printStackTrace();
			}
		}
		return null;
	}
	
	/**
	 * 获取按钮属性信息
	 * @param action_id 按钮编号
	 * @param pro_name 获取属性
	 * @return
	 */
	public static String getActionPro(String action_id,String pro_name) {
	   String val = null;
	   Dto actionDto = null;
       Dto acDto = getContextProperty(CTConstants.CT_ACTION_LIST);
       if(CTUtils.isNotEmpty(acDto)){
    	   actionDto = (BaseDto)acDto.get(action_id);
    	   if(CTUtils.isNotEmpty(actionDto)){
    		   val = actionDto.getAsString(pro_name);
    		   StringUtil.xprint("获取按钮属性["+pro_name+"]的值为："+val);
    	   }
       }
       return val;
	}
	
	/**
	 * 获取菜单属性信息
	 * @param menu_id 按钮编号
	 * @param pro_name 获取属性
	 * @return
	 */
	public static String getMenuPro(String menu_id,String pro_name) {
	   String val = null;
	   Dto menunDto = null;
       Dto meDto = getContextProperty(CTConstants.CT_MENU_LIST);
       if(CTUtils.isNotEmpty(meDto)){
    	   menunDto = (BaseDto)meDto.get(menu_id);
    	   if(CTUtils.isNotEmpty(menunDto)){
    		   val = menunDto.getAsString(pro_name);
    		   StringUtil.xprint("获取菜单属性["+pro_name+"]的值为："+val);
    	   }
       }
       return val;
	}
	
	
	/**
	 * 获取指定字典参数集合
	 * @param code_name
	 * @return
	 */
	public static List<Dto> getCodeList(String code_name) {
		
		List<Dto> rList = null;
		List<Dto> rList2 = null;
		Dto codeDto = (BaseDto)getContextAtrribute(CTConstants.CT_CODE_LIST);
		List<Dto> cList = codeDto.getAsList(code_name);
		if(CTUtils.isNotEmpty(cList)){
			Dto reDto = null;
			rList = new ArrayList<Dto>();
			for (int i=0;i<cList.size();i++) {
				reDto = (BaseDto)cList.get(i);
				if(!"-9".equals(reDto.getAsString("code_value"))){
					rList.add(reDto);
				}
			}
			
			//排序
			rList2 = StringUtil.sortDtoList(rList, "sort_no", "asc");
		}
		return rList2;
	}

	
	/**
	 * 根据值获取字典描述
	 * @param coList
	 * @param code_value
	 * @return
	 */
	public static String getCodeName(String field_code,String code_value) {
		String retStr = "";
		List<Dto> coList = getCodeList(field_code);
		if(CTUtils.isNotEmpty(coList)){
			for (Dto dto : coList) {
				if(code_value.trim().equalsIgnoreCase(dto.getAsString("code_value"))){
					retStr = dto.getAsString("code_desc");
					//StringUtil.xprint("code_desc="+retStr);
					break;
				}
			}
		}
		return retStr;
	}
	
	/**
	 * 根据值获取字典值
	 * @param coList
	 * @param code_desc
	 * @return
	 */
	public static String getCodeValue(String field_code,String code_desc) {
		String retStr = "";
		List<Dto> coList = getCodeList(field_code);
		if(CTUtils.isNotEmpty(coList)){
			for (Dto dto : coList) {
				if(code_desc.trim().equalsIgnoreCase(dto.getAsString("code_desc"))){
					retStr = dto.getAsString("code_value");
					//StringUtil.xprint("code_value="+retStr);
					break;
				}
			}
		}
		return retStr;
	}
	
	
	/**
	 * 根据值获取字典值
	 * @param coList
	 * @param code_desc
	 * @return
	 */
	public static String getIndxCodeValue(String field_code,String code_value,String index) {
		String retStr = "";
		List<Dto> coList = getCodeList(field_code);
		if(CTUtils.isNotEmpty(coList)){
			for (Dto dto : coList) {
				if(code_value.trim().equals(dto.getAsString("code_value"))){
					retStr = dto.getAsString(index);
					//StringUtil.xprint("index_value="+retStr);
					break;
				}
			}
		}
		return retStr;
	}
	
	/**
	 * 获取容器路径
	 * @param classPath
	 * @param flag
	 * @return
	 */
	public static String getWebRootPaht(String classPath,int flag) {
		String tomcatPath = "";
		String mediaPath = "";
		String imagePath = "";
		String returnPath ="";
		if(classPath.charAt(0)=='/'){
	    	classPath = classPath.substring(1,classPath.length());
	    }
		if(classPath.contains("%20")){
		   classPath = classPath.replaceAll("%20", " ");
		}
		if(classPath!=null&&!"".equals(classPath)){
			int index = classPath.indexOf("/webapps")+8;
			if (index > 0 && index < classPath.length()) {
				tomcatPath = classPath.substring(0, index);
				mediaPath = tomcatPath + "/mediaFolder";
				imagePath = tomcatPath + "/imageFolder";
			}
			System.out.println("tomcatPath="+tomcatPath);
			System.out.println("mediaPath="+mediaPath);
			System.out.println("imagePath="+imagePath);
		}
		if(flag==0){
			returnPath =tomcatPath;
		}
		if(flag==1){
			returnPath = imagePath;			
				}
		if(flag==2){
			returnPath = mediaPath;
		}
		return returnPath;
	}
	
	/**
	 * 将ISO8859_1编码的字符串转化为UTF-8编码的字符串 主要用来处理中文显示乱码的问题
	 * 
	 * @param ISO8859_1str
	 *            通过ISO8859_1编码的字符串
	 * @return 通过UTF-8编码的字符串
	 * @throws UnsupportedEncodingException
	 */
	public static String CharsetFilter(String keys)
			throws UnsupportedEncodingException {
		// 将参数UTF-8编码
		String value1 = keys;
		value1 = new String(value1.getBytes("ISO8859-1"), "UTF-8");
		System.out.println("utf-8==" + value1);
		return value1;
	}
	
	/**
	 * 字符转码
	 * 
	 * @param str
	 * @return
	 */
	public static String CCharseter(String str, String set) {
		try {
			if (str != null && !"".equals(str)) {
				return new String(str.getBytes("ISO8859-1"), set);
			}
		} catch (Exception e) {
			e.printStackTrace(); // 输出堆栈信息
		}
		return null;
	}
	
	 public static String replaceBlank(String str) {
        String dest = "";
        if (str!=null) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(str);
            dest = m.replaceAll("");
        }
        return dest;
    }
	 
	//处理空格
	public static String rhtml(String content){
		String html = content;
		html = html.replace("\r", "");
		html = html.replace("\n", "");
		html = html.replace("\t", "");
		return html;
	}
	

	
	public static void main(String[] args) throws UnsupportedEncodingException {
		/*Dto paramDto = new BaseDto();
		paramDto.put("contentPubTime","date$gt@2012-05-10");
		paramDto.put("collectTime","date$lt@2012-05-17");
		paramDto.put("contentTitle","string$湖南美女");
		paramDto.put("contentID","numeric$eq@2145212");
		paramDto.put("contentStatu","boolean$true");
		getFilterDto("contentID,contentTitle,siteName,collectTime,contentPubTime,contentStatu",paramDto);*/
		
		//String str = getCurrentMonthLastDay(strToDateTime("2012-09-10 23:59:59"));
		//StringUtil.xprint(str);
		
		//String wodString = getSpellWord("所发生地方",false);
		//StringUtil.xprint("wodString=="+wodString);
		//StringUtil.xprint("path=="+getWebRootPaht(CTUtils.class.getResource("/").toString(), 1));
		StringUtil.xprint(replaceBlank("just do it!"));
		StringUtil.xprint(CTUtils.encryptBasedDes("inter13666183427@163.com"));
		StringUtil.xprint(CTUtils.encryptBasedDes("interbcqlKJ20140618"));
		StringUtil.xprint(CTUtils.decryptBasedDes("naI2EaP+0k3RYhQpmpbX3w=="));
		StringUtil.xprint(CTUtils.decryptBasedDes("yWZLRn0YBB27MGpwi8z9yQ=="));
		StringUtil.xprint("RaFutWeh0ww=");
		BigDecimal bd = new BigDecimal("3.40256010353E11");  
		StringUtil.xprint(bd.toPlainString());
	}
}